mod config;
mod notif;
mod sse;
use std::{ops::Deref, sync::Arc};

use anyhow::Result;
use axum::{
    middleware::from_fn_with_state,
    response::{Html, IntoResponse},
    routing::get,
    Router,
};
use chat_core::{auth::verify_token, error::AppError, jwt::DecodingKey, TokenVerify, User};
use config::AppConfig;
use dashmap::DashMap;
pub use notif::setup_pg_listener;
use notif::AppEvent;
pub(crate) use sse::*;
use tokio::sync::broadcast;

pub type UserMap = Arc<DashMap<i64, broadcast::Sender<Arc<AppEvent>>>>;

const INDEX_HTML: &str = include_str!("../index.html");
#[derive(Clone)]
pub struct AppState(Arc<AppStateInner>);

pub struct AppStateInner {
    pub config: AppConfig,
    pub users: UserMap,
    pub dk: DecodingKey,
}

impl TokenVerify for AppState {
    type Error = AppError;
    fn verify(&self, token: &str) -> Result<User, Self::Error> {
        self.dk.verify(token)
    }
}
impl Deref for AppState {
    type Target = AppStateInner;
    fn deref(&self) -> &Self::Target {
        &self.0
    }
}
pub fn get_router() -> (Router, AppState) {
    let config = AppConfig::load().expect("load config failed");
    // let pk = &config.auth.pk;
    let app_state = AppState::new(config);
    let router = Router::new()
        .route("/events", get(sse_handler))
        .layer(from_fn_with_state(
            app_state.clone(),
            verify_token::<AppState>,
        ))
        .route("/", get(index_handler))
        .with_state(app_state.clone());
    (router, app_state)
}

async fn index_handler() -> impl IntoResponse {
    Html(INDEX_HTML)
}

impl AppState {
    fn new(config: AppConfig) -> Self {
        let dk = DecodingKey::load(&config.auth.pk).expect("load pk failed");
        let users = Arc::new(DashMap::new());
        Self(Arc::new(AppStateInner { config, users, dk }))
    }
}
